package common.dal;

import java.util.EnumSet;

import common.Pair;

/**
 * Represents an SQL column
 * 
 * @author Gal Lalouche
 */
public class SQLDataColumn {
	/**
	 * Constraints against the column
	 * 
	 * @author Gal Lalouche
	 */
	public enum Constraints {
		/**
		 * Column cannot be null
		 */
		NOT_NULL,
		/**
		 * Column must be unique
		 */
		UNIQUE,
		/**
		 * Column is the row's primary key
		 */
		PRIMARY_KEY,
		/**
		 * Column is also a primary key to another table; extra data must contain a {@link Pair} of the (table, foreign
		 * key)
		 */
		FOREIGN_KEY,
		/**
		 * The column has a default value; extra data must contain the dafault value
		 */
		DEFAULT,
		/**
		 * The column will be indexed for easy searching
		 */
		INDEX;
		@Override
		public String toString() {
			switch (this) {
			case NOT_NULL:
				return "not null";
			case PRIMARY_KEY:
				return "primary key";
			case FOREIGN_KEY:
				return "foreign key";
			default:
				return super.toString();
			}
		}
	}
	
	/**
	 * The default size of a varchar type
	 */
	public static int				VARCHAR_SIZE	= 50;
	
	private final String			name;
	private final SQLDataType		sqlType;
	private EnumSet<Constraints>	constraints;
	private final Object			extraData;
	
	/**
	 * Creates a new SQLDataColumn with multiple constraints
	 * 
	 * @param name The column's name
	 * @param sqlType The column's type
	 * @param constraints The column's constraints
	 */
	public SQLDataColumn(String name, SQLDataType sqlType, EnumSet<Constraints> constraints) {
		this(name, sqlType, constraints, null);
	}
	
	/**
	 * Creates a new SQLDataColumn with a single constraint
	 * 
	 * @param name The column's name
	 * @param sqlType The column's type
	 * @param constraint The column's constraint
	 */
	public SQLDataColumn(String name, SQLDataType sqlType, Constraints constraint) {
		this(name, sqlType, EnumSet.of(constraint));
	}
	
	/**
	 * Creates a new SQLDataColumn with no constraints
	 * 
	 * @param name The column's name
	 * @param sqlType The column's type
	 */
	public SQLDataColumn(String name, SQLDataType sqlType) {
		this(name, sqlType, EnumSet.noneOf(Constraints.class));
	}
	
	/**
	 * @param name The column's name
	 * @param sqlType The column's type
	 * @param constraints The column's constraints
	 * @param extraData Any extra data associated with the column
	 */
	public SQLDataColumn(String name, SQLDataType sqlType, Constraints constraints, Object extraData) {
		this(name, sqlType, EnumSet.of(constraints), extraData);
	}
	
	/**
	 * Creates a new SQLDataColumn with multiple constraints and extra data associated with column
	 * 
	 * @param name The column's name
	 * @param sqlType The column's type
	 * @param constraints The column's constraints
	 * @param extraData Any extra data associated with the column
	 */
	public SQLDataColumn(String name, SQLDataType sqlType, EnumSet<Constraints> constraints, Object extraData) {
		if (name == null) {
			throw new IllegalArgumentException("name is null");
		}
		if (sqlType == null) {
			throw new IllegalArgumentException("sqlType is null");
		}
		
		if (constraints == null) {
			this.constraints = EnumSet.noneOf(Constraints.class);
		} else {
			this.constraints = constraints;
		}
		assert constraints != null;
		if (constraints.contains(Constraints.DEFAULT) && (extraData == null)) {
			throw new IllegalArgumentException("extra data cannot be null if using " + Constraints.DEFAULT);
		}
		if (constraints.contains(Constraints.FOREIGN_KEY) && (extraData == null)) {
			throw new IllegalArgumentException("extra data cannot be null if using " + Constraints.FOREIGN_KEY);
		}
		this.name = name;
		this.sqlType = sqlType;
		this.extraData = extraData;
	}
	
	@Override
	public String toString() {
		return "[" + getName() + ", " + getSQLDataType() + ", " + getConstraints() + ", " + getExtraData() + "]";
	}
	
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * @return the sqlType
	 */
	public SQLDataType getSQLDataType() {
		return sqlType;
	}
	
	/**
	 * @return the constraints
	 */
	public EnumSet<Constraints> getConstraints() {
		return constraints;
	}
	
	/**
	 * @return the extraData
	 */
	public Object getExtraData() {
		return extraData;
	}
	
}
